package org.example;

import java.util.ArrayList;

public class Main {
    static final int THREAD_NUMBER = 2;
    static final int LOOP_NUMBER = 200;
    public static void main(String[] args) {
//        ThreadUnsafe test = new ThreadUnsafe(); //情况1
//        ThreadSafe test = new ThreadSafe(); //情况2
        ThreadSafeSubClass test = new ThreadSafeSubClass();//情况3
        for (int i = 0; i < THREAD_NUMBER; i++) {
            new Thread(() -> {
                test.method1(LOOP_NUMBER);
            }, "Thread" + i).start();
        }
    }

}
//情况1
//list为成员变量,需要考虑线程安全问题
//class ThreadUnsafe {
//    //成员变量被共享,同时被多个线程进行写操作,会产生竞态条件，导致线程不安全
//    ArrayList<String> list = new ArrayList<>();
//    public void method1(int loopNumber) {
//        for (int i = 0; i < loopNumber; i++) {
//            // { 临界区, 会产生竞态条件
//            method2();
//            method3();
//            // } 临界区
//        }
//    }
//    private void method2() {
//        list.add("1");
//    }
//    private void method3() {
//        list.remove(0);
//    }
//}

//情况2 ①
//list为局部变量,不需要考虑线程安全问题
//每个线程调用method1()时,都会创建独立的list实例,不会共享变量
//class ThreadSafe {
//    public final void method1(int loopNumber) {
//        ArrayList<String> list = new ArrayList<>();
//        for (int i = 0; i < loopNumber; i++) {
//            method2(list);
//            method3(list);
//        }
//    }
//    private void method2(ArrayList<String> list) {
//        list.add("1");
//    }
//    private void method3(ArrayList<String> list) {
//        list.remove(0);
//    }
//}

//情况2 ②
//如果把method2()和method3()方法的访问权限改为public,则其他线程调用method2()和method3()方法,
//接收到的list参数不是本身线程创建的list对象,而是其他线程创建的list对象,所以线程安全
//class ThreadSafe {
//    public final void method1(int loopNumber) {
//        ArrayList<String> list = new ArrayList<>();
//        for (int i = 0; i < loopNumber; i++) {
//            method2(list);
//            method3(list);
//        }
//    }
//    public void method2(ArrayList<String> list) {
//        list.add("1");
//    }
//    public void method3(ArrayList<String> list) {
//        list.remove(0);
//    }
//}

//情况3
// 在 情况2 的基础上，为 ThreadSafe 类添加子类，子类覆盖 method3 方法
// 在main方法中创建子类对象, 线程0或线程1在访问method1时,局部变量list的引用暴露给了子类重写method3方法中的其他线程。
//所以父类方法的访问修饰符设为private化是有意义的,因为限制了子类不能够覆盖这个方法。其次如果希望被public修饰的方法不能够被子类重写,可以添加final关键字.
//那
class ThreadSafe {
    public final void method1(int loopNumber) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < loopNumber; i++) {
            method2(list);
            method3(list);
        }
    }
    public void method2(ArrayList<String> list) {
        list.add("1");
    }
    public void method3(ArrayList<String> list) {
        list.remove(0);
    }
}
class ThreadSafeSubClass extends ThreadSafe{
    @Override
    public void method3(ArrayList<String> list) {
        new Thread(() -> {
            list.remove(0);
        }).start();
    }
}